perm filename FAIL.PMP[S,DOC]1 blob
sn#002740 filedate 1972-06-11 generic text, type T, neo UTF8
STANFORD ARTIFICIAL INTELLIGENCE PROJECT April 1970
OPERATING NOTE No. 26.2
FAIL MANUAL
P. M. Petit
The work reported here was supported in part by the
Advanced Research Projects Agency of the Department of
Defense under contract SD-183.
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 1
1.0 FAIL STATEMENTS
INTRODUCTION
FAIL is the good symbolic assembly program for the PDP-6 or PDP-10.
This assembler performs many useful and unique functions, making
machine language programming easier, faster, and more efficient.
FAIL is a one-pass assembler, which means that it reads the input
file only once. This and other efficiencies which have been employed
in its coding make FAIL at least five times as fast as the other
leading brand of assembler for the PDP-10.
Basically, the assembler processes the programmer's source program
statements by translating mnemonic operation codes to the binary
codes needed in machine instructions, relating symbols to numeric
values, assigning relocatable or absolute core addresses for program
instructions and data, and preparing an output listing of the
program, which includes notification of any errors detected during
the assembly.
FAIL also has a powerful macro processor which allows the programmer
to create new language elements, thus expanding and adapting the
assembler to perform special functions for each programming job.
1.1 FAIL LANGUAGE -- STATEMENTS
A FAIL program consists of a string of statements, usually one to a
line, which is read from one or more input files. A statement
usually has one or more of the following elements, arranged as
follows:
LABEL: OPERATOR OPERAND(s) (carriage return-line feed)
A statement must contain at least one of these elements, or it is a
blank line. Blank lines generate no code and are not considered
statements.
The binary words (code) which the assembler translates statements
into, are normally placed in successively increasing locations when
they are loaded by the loader. The assembler uses a counter called
the location counter to keep track of the location into which it
should place the next word. Each time the assembler generates a word
of binary from a statement, the location counter is increased by one.
The location counter thus contains the address of the location into
which the next word generated will be placed.
1.1.1 LABELS
A label is the symbolic name, created by the source programmer
(that's you) to identify a location in the object (binary) program.
When a label is encountered, the label is given the value of the
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 2
address currently in the location counter. This means that if a
statement starts with a label, the label (symbol) will be given the
value of the address of the core location into which the code
generated for that statement will be placed. Hence that label will
refer to the statement it appears in. See symbolic addresses below.
More than one label may appear on one line, in which case all are
given the same value. Note also that if a label (or several labels)
is the only thing on a line, the line will not generate any code, and
the label will have the same value it would have if it appeared on
the next line instead.
A label need not be the first thing one a line. It may appear after
the operator, between operands, or at the end of the line. In all of
these cases, the label will have the same value. A label, of course,
cannot appear in a comment (see below).
A label consists of a symbol (see below) followed by a colon (:). One
or more spaces may appear between the symbol and the colon, and these
are ignored if present.
1.1.2 OPERATORS
An operator may be one of the semi-infinite number of machine
instruction mnemonics or UUO mnemonics (if an appendix appears at the
end of this write-up, there is probably a listing of these mnemonics
there), an assembler pseudo-op (see the pseudo-op section), or a
user-defined operation code (see OPDEF in pseudo-op section). An
operator, if it appears, must be the first thing on the line besides
labels and/or assignment statements (see assignment statements,
below). If the first thing on a line (besides labels and assignment
statements) is not a defined operator (op-code, pseudo-op, or OPDEF),
it is assumed by the assembler to be a symbolic reference (see
below). That is, it is assumed that there is no operator.
The value of an op-code (machine instruction or UUO mnemonic) is
placed in the op-code field of the binary word being assembled. The
effects of pseudo-ops and opdefs are listed with the appropriate
pseudo-ops in that section.
1.1.3 OPERANDS
There are three types of operands which appear after an op-code (or
opdef). (See the individual pseudo-op for the operands which appear
with it.) The three types are: address field, index field, and
accumulator (AC) field. An operand consists of an expression (see
below) accompanied by the characters, if any, which identify the type
of field. An expression which is followed, immediately or with
intervening spaces, by a comma (,), is the AC (accumulator) field,
and its value is placed in the accumulator field of the word being
assembled. An expression which is enclosed, in its entirety, in
parentheses is the index field. The right half (18 bits) is "ored"
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 3
into the left half of the word being assembled. If no address field
has appeared on the line before the index field, the left half of the
value of the index field is placed in the right half (address field)
of the word being assembled. An expression which is not followed by
a comma and not entirely enclosed in parentheses, and which is either
not defined as an operator or not the first thing on the line besides
labels or assignment statements, is an address field. The value of
an address field is placed in the address field (right half) of the
word being assembled. Only one address field is allowed per
statement.
1.1.4 COMMENTS
If a semi-colon (;) appears on a line, all characters between it and
the next line feed are totally ignored by the assembler. (The only
exceptions have to do with MCAROs and REPEAT, etc. See the macro
section.) This is an excellent place for the programmer to put
comments and other forms of graffiti which might otherwise confuse
the assembler.
1.1.5 OTHER NONSENSE
If one or more at-sign characters (@) appear as part of a statement,
the indirect bit will be turned on in the word being assembled. The
at-sign(s) may appear anywhere on the line except in the comment or
imbedded inside symbols or expressions.
1.2 SYMBOLS
A symbol consists of a contiguous string of characters, the first of
which is a letter and the others of which are letters or digits. In
addition to A-Z and a-z, the three characters $ % and . are letters.
Any two symbols which have the first six characters the same will be
considered as identical by the assembler. In fact, any characters
beyond the sixth will be truncated on input. Symbols are also called
identifiers.
1.2.1 SYMBOLIC ADDRESSES
All values, including addresses, have two parts. The fist part is
the numeric value and the second is the relocation. Most values have
relocations of either 1 or 0. Values with 0 relocation are called
obsolute. Numbers, such as 1 or 37, are absolute. Values with a
relocation of 1 are called relocatable. Symbolic addresses (values of
labels) are usually relocatable. This is so the loader can load
programs anywhere in core. When the loader starts to load a program,
it defines the "relocation constant" for that program. This is the
absolute location which will be equivalent to relocatable 0, or, in
other words, the address at which the loader will, under ordinary
conditions, place the first word of the program. (Relocations other
than 1 or 0 may occur under certain circumstances.) All values are
passed to the loader along with relocation. The loader multiplies
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 4
the relocation by the relocation constant and adds the result to the
numeric value. Thus the loader can load a program anywhere, and
addresses will still refer to the words the programmer intended.
There are three ways a symbol may be given a value. One way is to
have the symbol appear as a label (i.e., appear on a line, followed
by a colon). This usually gives the symbol a relocatable value. The
second way to give a symbol a value is with the assignment statement.
An assignment statement consists of a symbol followed by a left arrow
(or two left arrows) followed by an expression. This gives the
symbol the value of the expression, which may be relocatable or
absolute or may have some other relocation. Assignment statements
may appear anywhere a label may appear, and have no effect on the
rest of the line they appear on. More than one assignment statement
may appear on a line.
Also, more than one symbol may be given a value with one statement.
See last example below.
A1 ← 7
BQZRN ← 137 + 52 -22 * 3
FONLY ← FOOBAZ +1
GARP ← Foo ← BAZ ← ZOT ← Mumble ← 27
A symbol may be redefined using an assignment statement, but an
attempt to redefine a symbol as a label (with a colon) will result in
a multiple-definition error message and the retention of the old
value.
If two left arrows are used with a symbol in an assignment statement,
that symbol will be defined in the normal way, but in the symbol
table which DDT will see, a bit will be turned on so that DDT will
not use that symbol in typing out expressions. This is equivalent to
saying $K in DDT.
The third way of defining a symbol is by following one or more of its
uses with a number sign (#). This makes the symbol a variable and
the assembler will set aside an empty cell with that name at the end
of the program (with the literals) unless the VAR pseudo-op is used
(see VAR).
Examples:
MOVEM A,FOO#
MOVEI B,BAZ#-1
Variables defined this way are local to the block in which they
appear with the #. Thus if FOO# appears in two blocks, two different
versions of FOO will be created. If this is not desired, see the
INTEGER pseudo-op.
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 5
1.2.2 SPECIAL CONSIDERATIONS
The symbol . (dot) has a special predefined value, which cannot be
changed. This value is that of the location counter, that is, the
value which would be given a label if it appeared on that line.
Thus:
FOO: JRST FOO
is equivalent to
FOO: JRST .
1.3 NUMBERS
The FAIL input scanner considers numbers to be in base 8 (octal)
unless the radix is changed using the RADIX pseudo-op. (See RADIX
pseudo-op). This pseudo-op may be used to set the input base (called
the "current radix") to almost anything else. A digit string
consists of a string of digits (0 to 9), and a number may be a single
digit string, in which case its value as the value of that number in
the current radix. A number may also consist of an equal sign (=)
followed by a digit string, in which case the digit string will be
interpreted in base 10 (decimal) regardless of the current radix.
Examples:
1743
2
=100
1.3.1 FLOATING POINT NUMBERS
Another form of number which may be used with FAIL consists of a
digit-string (with at least one digit) followed by the letter .
(decimal point) followed by a digit string (which may be empty). This
number will be interpreted in base 10 (decimal) regardless of the
current radix, and will be put into PDP-6/10 floating-point format.
A floating point number may be followed by an exponent. This
consists of the letter E followed by an optional plus or minus sign,
and one or two digits. The number following the E is interpreted in
base 10 (decimal) and the floating point number is multiplied by that
power of 10.
Examples:
10.7E1 (Equivalent to 107.0)
9.973
0.13
10.
1.86E05
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 6
31.4159E-1
1.3.2 BINARY SHIFTING
Any number may be followed by the letter B followed by one or two
digits. The value of this new number will be that of the old number,
shifted (logically) until the low order bit is in the indicated bit
position. Thus, B35 will have no effect on the value of a number, and
B34 will shift left by one. Note that the number following the B
will be interpreted in decimal.
Examples:
254B8
1B33 (equivalent to 4)
=10B27
22B18
No number may have an imbedded space. Therefore, no spaces may
appear between successive digits in a digit string, or between a
digit string and a B which is intended for shifting, or following the
B, or before or after the E of an exponent, etc.
1.3.3 ASCII and SIXBIT Numbers
A string consisting of a double-quote (") followed by a string of
characters not including double-quote, followed by a double quote,
has the value of the right-adjusted 7-bit ascii for the characters in
the string, not including the double quotes. If more than five
characters appear, the high-order parts of the value will be lost
(i.e. the value is only the right-hand 36 bits). Also, a string
consisting of a single quote (') followed by a string not containing
single quote, followed by a single quote, has the value of the
right-adjusted sixbit for the characters in the string. Again, the
high-order bits are lost if there are more than six characters.
Both of these constructions are considered numbers, except that they
may not be followed by the B construction for shifting.
1.4 EXPRESSIONS
An expression consists of operands connected by operators.
1.4.1 Operators.
FAIL recognizes the following operators:
Symbol Meaning Priority Level
+ PLUS 1
- (binary) MINUS 1
* TIMES 2
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 7
/ DIVIDED-BY 2
∧ AND 3
∨ OR 3
≠ XOR 3
⊗ LEFT-SHIFT (logical) 4
- (unary) MINUS
(two's complement) 5
¬ (unary) NOT
(one's complement) 5
Also, since some of these characters can't be typed on the teletype,
the following equivalences are recognized by FAIL:
& same as ∧
! same as ∨
⊗ may be typed in as control V
≠ and ¬ have no teletype equivalents. You lose.
1.4.2 Operands.
Operands may be symbols, numbers, or expressions enclosed in
parentheses. They may also be literals (see literals) or lines
enclosed in "pointy brackets" (or brokets) (< >). This latter
construction has the value of the 36-bit word which the assembler
would generate for the line inside the brokets, if it appeared on a
line by itself. (In the case of pseudo-ops which generate more than
one word of code, the value is the first word generated.) Note that
this construction does not, of itself, actually generate any code.
For example, since the line:
JRST 4,37
would generate the word 254200 000037, the value of the expression:
<JRST 4,37> + 102
is: 254200 000141
This construction is particularly handy for such things as:
MOVSI A, (<JRST 4,>)
TLO B,(<MOVEI>)
1.4.3 Evaluation of Expressions.
The operators in expressions are evaluated in order of priority.
Thus, first all unary operators are evaluated (NOT and unary MINUS),
then all left shifts are evaluated, then all AND's, OR's and XOR's,
and so forth until all PLUS's and MINUS's have been evaluated. This
order of evaluateion may be changed by the use of parentheses.
However, if the entire expression is enclosed in parentheses, it will
be considered to be the index field (except in assignment
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 8
statements).
1.4.4 Relocation and Definition.
Note that the relocation for an expression may be other than 1 or 0.
For example, the relocation of the sum of two relocatable symbols is
2. In fact, in the case of multiplication, division, shifting, and
the logical operators, the relocation may be quite difficult to
evaluate. In all cases where the relocation of an expression is other
than 1 or 0, or is difficult to evaluate, the assembler instead
converts the expression to Polish and saves the Polish. Under some
circumstances, the Polish may be passed to the loader for evaluation.
Under other circumstances, the assembler will evaluate it itself,
later. In all cases, the right thing happens.
Also, an expression may contain symbols which are defined later in
the program (called forward references), or which are external to the
program. In these cases, the expression is difficult to evaluate and
the assembler again saves the Polish.
However, the saving of Polish takes up assembler core space rapidly
and, when the Polish must be passed to the loader, the binary file
tends to get long. Therefore, if either of these considerations
becomes important, care should be taken to avoid such expressions.
1.5 LITERALS (pronounced as though it had been misspelled LITTERALS).
A literal consists of a left square bracket ([) followed by some
text, followed by a right square bracket (]). The assembler
assembles the text between the square brackets and places the
generated code at the end of the program (unless the LIT pseudo-op is
used. See LIT pseudo-op.) The value of the literal is the address at
which the generated code is placed. If the text generates more than
one word of code, the value will be the address of the first word.
Thus, the following two programs will generate the same code:
START: MOVE 1,LIT
JRST .-1
LIT: JRST 4,START
END
-------------------------------------
START: MOVE 1,[JRST 4,START]
JRST .-1
END
A literal may embrace more that one line of text, and literals may be
used recursively. The following are examples of the legal use of
literals:
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 9
MOVE 1,[MOVE 2,[JRST 3]]
FAD 3,[1.0]
PUSHJ P,[MOVE A,NUM
ADD B,TAB(A)
MOVEM B,(C)
POPJ P,]
MOVEI A,[ASCIZ/ NOW IS THE TIME
/]
JRST [MOVE A, [ABCA-ZOT]
ADD B,C
IDIV B,[L-QRN]
JRST .+1]
Note that the symbol . retains its value in the main stream of code.
Thus the JRST .+1 in the last example above will return to the main
stream, i.e. to the instruction following the first JRST. Labels may
be used inside the literals and will refer to the location where that
word of literal is finally stored. In this case FOO: is not the same
as FOO←..
1.6 BLOCK STRUCTURE
FAIL allows the programmer to use a form of block structure which is
quite similar to the traditional form. The programmer is able to set
off certain sub-sets of his program as blocks. The assembler
considers the whole program proper as one block, and this is the
outermost block. It may contain a number of blocks, and each of
these may contain blocks. There is no limit to the number of blocks
a program may or a block may contain. There is, however, a limit to
the maximum depth of the block structure, that is, the number of
blocks which can be nested within one another. This limit is 17
(decimal).
The purpose of block structure is to make possible the multiple use
of the names of labels, op-defs, and macros. If the definition of a
label, op-def, or macro occurs inside a block, that definition
ordinarily applies only inside that block and does not conflict with
definitions of labels, op-defs or opcodes of the same name in other
blocks.
Ideally, if a label, op-def, or macro is defined in a given block,
that definition applies in that block, and that symbol is considered
to be undefined in the block which the given block is part of, unless
it is defined separately in that (next-outer) block. However, if the
given block has a sub-block as part of it, that definition applies
within this (inner) block, unless the symbol has another definition
within this (inner) block. This is indeed the case with op-defs and
macros, except that forward references to macro and op-defs are not
permitted. Thus, if it is desired that an inner block have a
different definition of a macro or op-def from that in the outer
block, that definition must be given in the inner block, before the
first reference to it in that block. Otherwise, the definition in
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 10
the outer block will be used for those references to it which occur
before the inner block definition. Labels do not have this problem,
since forward references to labels are permitted.
However, there is another difficulty with labels in block structure,
which does not occur for op-defs and macros. The difficulty is that,
for labels, there is an inherent connection between the value given a
label and the location in the program at which the definition is
made. Thus it is not possible, with the ordinary mechanism, to define
a label as referring to an instruction in an inner block, and to make
the definition available in an outer block. To get around this
difficulty, if a label definition or assignment statement is preceded
by an up-arrow (↑), that definition is made available to the next
outer block. (If the definition is preceded by two up-arrows (↑↑),
the definition is made available to all outer blocks). This is as
though the definition had been made in the outer block, except that
the label cannot have a different value in the inner block.
An inner block is entered with the BEGIN pseudo-op. The current
block is ended with the BEND statement. Thus a block is surrounded
by a BEGIN and BEND. For details of these pseudo-ops, see the
pseudo-op section.
Example of the use of block structure. These two programs generate
the same code:
FOO1: JRST FOO1 FOO1: JRST FOO1
JRST FOO2 JRST FOO2
JRST FOO3 JRST FOO3
BEGIN
FOO2: JRST FOO1 FOO22: JRST FOO1
↑FOO3: JRST FOO2 FOO3: JRST FOO22
JRST FOO3 JRST FOO3
BEGIN
JRST FOO1 JRST FOO13
JRST FOO2 JRST FOO22
JRST FOO3 JRST FOO3
FOO1: JRST FOO4 FOO13: JRST FOO4
BEND
↑FOO4: JRST FOO4 FOO4: JRST FOO4
BEND
FOO2: JRST FOO4 FOO2: JRST FOO4
There is one other problem with block structure, and that has to do
with the accumulator and index fields. Since the assembler has no
way of knowing if a symbol will be defined later in a block, a
reference to a symbol which has not been explicitly defined in this
block must be treated as a forward reference until either a
definition or the end of a block is encountered, even if the symbol
has a definition in the next-outer block. Such symbols are said to
be not available, even though they are defined. Since forward
SAILON 26.2 FAIL MANUAL FAIL STATEMENTS 11
references are not permitted in accumulator or index fields, (i.e.
symbols in AC or index fields must be available) there are two kluges
by which it is possible to make accumulator symbols explicitly
available in inner blocks, without the necessity of redefining them
in each block. That is, there are two ways of making such
definitions global. One of these kluges is the GLOBAL pseudo-op,
which will not be discussed here (see pseudo-op section). The other,
which is more useful in most cases, is the use of down-arrow (↓). If
a label definition or assignment is preceded by a down-arrow (↓),
that definition will be immediately available to any references to
the symbol in inner blocks. If a symbol which has been defined with
down-arrow is redefined in an inner block, that redefinition holds
for that block only and does not affect the definition in outer
blocks.
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 12
2.0 PSEUDO-OPS
2.1 DESTINATION OF ASSEMBLED CODE
As was stated earlier, the assembler uses a location counter to keep
track of the location where the code it is assembling will go. This
counter is normally initialized to relocatable 0 at the start of the
assembly and is incremented by 1 for each instruction assembled. The
value in the location counter is the location where the next word
assembled will go. The contents of the location counter can be
changed with the LOC, RELOC, and ORG statements.
2.1.1 LOC
The LOC pseudo-op takes one operand, an expression, which must be
defined (and available). The effect of LOC is to put the value of
the operand into the location counter and to set the relocation of
the counter to absolute (regardless of the relocation of the
argument).
2.1.2 RELOC
The RELOC statement has the same effect as the LOC statement except
that the relocation is set to relocatable regardless of the
relocation of the argument.
2.1.3 ORG
The ORG statement has the same effect as the LOC or RELOC statements
except that the relocation is set to the relocation of the argument.
Whenever LOC, RELOC or ORG is used, the current value of the location
counter is saved (along with its relocation). A LOC, RELOC, or ORG
statement with no argument will cause the preserved value and
relocation to be put into (swapped with) the location counter.
2.1.4 Other Location Counters.
It is possible to have more than one location counter and to switch
back and forth among them. Location counters may be given any names
which fit the syntax of identifiers. The SET pseudo-op is used to
initialize a location counter. It takes two arguments. The first is
the name of the location counter and the second is the value to which
the counter should be set. The arguments should be separated by a
comma. SET has the same effect as ORG except that it changes the
indicated location counter and has no effect on the current location
counter unless it is the same as the indicated one. SET is usually
used to create a new location counter.
The USE pseudo-op is used to change location counters. It takes one
argument, the name of the location counter to change to. USE causes
the current location counter value to be saved away and the value of
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 13
the indicated counter to be used. If a subsequent USE indicates the
location counter which was saved away, the value it had when it was
saved away will become the current value. Only the currently active
location counter is incremented. If the indicated location counter
has not appeared before its appearance in a USE (i.e., if it has no
value), it will be given the value of the current location counter.
The location counter which the assembler starts with has a blank name
(i.e., a null argument indicates this first one).
Example:
Location: Instructions:
0' JRST FOO
1' JRST BAZ
2' SET GARP, 37
2' USE GARP
37 JRST FOO
40 USE
2' JRST FOO
Note: There is no relationship between location counters and labels
with the same name; just as there is no relationship between labels
and blocks with the same name.
2.1.5 Phase-Dephase
It is sometimes desired to assemble code in one place which will
later be moved by the program itself to another place. In this case,
it is desired that labels be defined as referring to locations in the
place where the code will be moved, rather than where the assembler
will put it. To accomplish this, the PHASE pseudo-op is used. PHASE
has one argument, the location to which the next word assembled will
moved by the program. For instance, if, while the location counter is
at 74, a PHASE 32 appears, and a label appears on the next line, the
label will be given the value 32, but the code on that line will be
placed in location 74. The DEPHASE pseudo-op (no argument) cancels
the effect of any PHASE.
2.2 ENTERING DATA
The RADIX statement changes the prevailing radix until the next RADIX
statement is encountered. It has no effect on numbers preceded by =.
The one argument of RADIX is interpreted in the current radix unless
it is preceded by a =. Thus, the statement RADIX 10 will have no
effect. The radix may be set to almost anything, but for radices
above 10, there are no digits to represent 10, 11, etc. (Zero is not
permitted and 1 should be avoided if one is going to use the
arithmetic FOR or Macro arguments with this radix ).
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 14
2.2.2 DEC and OCT
The DEC and OCT statements each ake a string of arguments, each a
number, separated by commas. The radix is temporarily set, for the
one statement, to 10 for DEC or 8 for OCT. The numbers are placed in
successive locations.
2.2.3 BYTE
The BYTE statement is used to enter bytes of data. Arguments in
parentheses indicate the byte size to be used until the next such
argument. Other arguments are the Bytes. An argument may be any
defined (and available) expression. Arguments in parentheses (byte
size) are interpreted in decimal (base 10) and other arguements in
the prevailing radix. Bytes are deposited with the byte
instructions, so if a byte will not fit in what's left of the current
word, it will be put in the left part of the next. Unused parts of
words are filled with zeros. Byte size arguments are not surrounded
by commas, but other arguments are separated by commas. For
instance, the statement
BYTE (7) 3,5(11)6
will put two seven bit bytes, (3 and 5) and an 11 (decimal) bit byte
(6) in a word, left justified.
The first arguement of a BYTE statement must be a byte size
arguement. Two successive commas indicate a null argument which is
the same as 0.
2.2.4 POINT
The POINT pseudo-op (2 or 3 arguments) assembles one word, a byte
pointer. The first argument should be an expression and is
interpreted in decimal. The expression must be defined and
available. It indicates the byte size and its value is placed in the
size field of the assembled word. The second argument should contain
one or more of an index field, an address field, and an at-sign (@,
indirect). The last (3rd) field, if present, indicates the bit
position of the low order bit of the byte, i.e., its value is
subtracted from 35 (decimal) and placed in the position field. It is
interpreted in decimal and must be available. If the 3rd argument is
not present (no comma should be present in this case), the position
field is set to 36 (decimal), so that the first time the pointer is
incremented, it will point to the first byte of the word.
2.2.5 IOWD
IOWD is a permanently defined macro. Its definition is:
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 15
DEFINE IOWD (A,B)<
XWD -A, B-1>
2.2.6 XWD
The XWD statement (2 arguments) assembles a single word with the
value of the first argument in the left half and the value of the
second argument in the right half. Both arguments must be present.
XWD is the only way of creating a word with a forward reference in
the left half.
2.2.7 Text Statements
There are 4 text statements. They are ASCII, ASCIZ, ASCID, and
SIXBIT. All take, as argument, a string of characters starting and
ending with, and not otherwise containing, some non-blank character,
which serves as a delimiter. This delimiter should not be ← or :.
ASCII puts the 7-bit representation of each successive character in
the string (not the delimiter) in successive words, 5 characters per
word, until the string is exhausted. The low order bit of each word
and the left-over part of the last word are filled with zero. ASCIZ
is the same as ASCII, except that if the last character is the 5th of
a word, a word of zero is added at the end. This is to ensure that
there is at least one 0 byte at the end. ASCID works as ASCII except
that the low order bit of each word generated is a 1. SIXBIT works
as ASCII except that the characters are converted to the 6-bit
representation and packed 6 to a word. The low order bit is used in
this representation and so is not necessarily zero. The last word is
filled out with zeros if necessary. (ASCII is converted to SIXBIT by
replacing the 40 bit with the 100 bit and removing the 100 bit.)
2.2.8 RADIX50
This pseudo-op has one or two arguments (separated by a comma, if
two). The second or only argument should be a symbol, and the first,
if present, a number. The value is the Radix50 for the symbol with
the number or'ed into the high order six bits. The two low order
bits of the number are cleared before oring.
2.3 BLOCK
The block statement takes one argument. Its effect is to add the
value of the argument to the location counter, thus reserving that
many locations. The argument must be defined and available.
BLOCK N
is equivalent to
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 16
ORG . +N
2.4 ASSEMBLER CONTROL STATEMENTS
2.4.1 END
The END statement (1 argument) is the last statement of a program. It
signals the assembler to stop assembling and no text following it
will be processed. The argument, if any, is taken as the starting
address of the program. All outstanding variables and literals are
placed starting at the current value of the location counter when the
END is seen. (See below. Variables are symbols which appeared with
a #). Variables are put out first.
2.4.2 LIT
The LIT statement causes all literals which were defined up to the
LIT statement to be placed where the LIT statement occurs. The LIT
statement must not appear inside a literal.
2.4.3 VAR
The VAR statement causes all variables (variables are symbols which
were defined by having a # after one or more appearances) which
appeared with a # in this block (or a sub-block of this one) to be
placed where the VAR appears. VAR must not appear inside a literal.
2.4.4 TITLE
This statement should be followed by a string of characters, the
first part of which should be an identifier. That identifier is then
used as the program name which DDT will recognize. It is also taken
as the name of the outer-most block. The string of characters is
printed as a part of the heading to all pages subsequent to the one
on which the TITLE statement appears. There should be only one TITLE
statement per program. The title statement should appear before any
statement which generates code.
2.4.5 SUBTTL
This statement should be followed by a string of characters. That
string is then used as a sub-heading on all subsequent pages until
another SUBTTL appears.
Note: The string to be used in the heading for either TITLE or
SUBTTL is terminated by the first carriage-return or semi-colon.
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 17
2.4.6 BEGIN, BEND
The BEGIN statement is used to start a block. The block it starts
will end at the corresponding BEND statement. The BEGIN may be
followed by an identifier. If it is, the identifier will be taken as
the name of that block, which DDT will recognize. If no identifier
appears, the assembler will create one. All text following the
identifier and all text after BEND in a BEND statement is ignored
until the next line-feed. For a discussion of block structure, see
that section in the first chapter.
2.4.7 PAGE
This pseudo-op has the same function as a form-feed. It causes a
form-feed to be placed in the listing immediately following itself.
The effect is to skip to the top of the next page of listings.
2.4.8 LIST-XLIST
The XLIST statement causes listing to stop until the next LIST
statement. LIST causes listing to resume if it has been stopped by
an XLIST or XLIST1 statement. Otherwise it is ignored.
2.4.9 XLIST1
This statement has exactly the same effect as XLIST unless the /I
switch was used in the command string, in which case it is ignored.
2.4.9.5 XCREF - CREF
These turn off and on the emition of information to CREF. They have
no effect if /C was not used in the command string.
2.4.10 LALL-XALL
XALL causes the listing of the body of Macros, Repeats, and Fors to
stop; LALL causes it to start up again.
2.4.10.5 NOLIT
This has the same effect as /L in the command string.
2.4.11 OPDEF
The OPDEF statement has the following strange syntax:
OPDEF symbol [value]
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 18
The syntax is strange for compatability with existing, inferior
assemblers. The effect of OPDEF is to insert the symbol into the
op-code table with the indicated value. The symbol may then be used
as any other op-code. Note that the value may have bits in fields
other than the op-code field. In this case, these bits will be ored
with bits which are indicated where the symbol is used, in the case
of the AC, index or indirect fields. In the case of the address
field, any indicated address will replace the one in the OPDEF. The
value part of the OPDEF must be defined and available.
2.4.12 EXTERNAL
EXTERNAL must be followed by a list of symbols separated by commas.
The effect is to tell the assembler that these symbols are defined in
a different program and are declared INTERNAL (see below) there. The
loader will then fix up the references to these symbols when the two
programs are loaded. EXTERNAL symbols must not be defined in the
program in which they are external.
2.4.13 INTERNAL
This statement declares that certain symbols should be made available
to other programs by the loader. See EXTERNAL above. INTERNAL should
be followed by a list of symbols. These symbols need not necessarily
be defined before the INTERNAL statement appears, but they must be
defined by the end of the program.
2.4.13.5 ENTRY
If used, this statement must appear before all other statements. It
has the same format and the same effect as INTERNAL except that it
emits special library entry blocks to the loader.
2.4.14 COMMENT
The first non-blank character following the COMMENT op-code is taken
as the delimiter. All text from it to the line-feed following the
next occurrence of this delimiter is totally ignored by the
assembler.
2.4.15 GLOBAL
The global pseudo-op should be followed by a list of symbols
separated by commas. Each symbol should be defined in an outer
block. The effect of GLOBAL is to find te next outer block in which
that symbol is defined and to make the definition in that block
immediately available in the block in which the GLOBAL appears.
GLOBAL does not affect the definition of the symbol in any
intervening blocks.
SAILON 26.2 FAIL MANUAL PSEUDO-OPS 19
If a symbol has been declared GLOBAL in the current block, and the
symbol is then redefined in this block, that redefinition is made
also on the definitions in the outer block where GLOBAL found the
definition. Doing this causes strange effects if the definition was
not in the next-outer block and it should not be done without some
careful thought.
2.4.16 LINK-LINKEND
The format is LINK(END) number, location. These pseudo-ops generate
loader block type 11. See Sailon 46 for more information.
2.4.17 INTEGER
This pseudo-op should be followed by a string of symbols, separated
by commas. Each of these symbols is then treated as though it had
appeared in the block where the INTEGER appears, followed by a #.
2.4.18 ARRAY
The format is ARRAY symbol [number],..... This is like INTEGER
except that "number" locations are set aside as a block, symbol being
the address of the first one.
2.5 PRE-DEFINED OP CODES
The usual op-codes of the PDP-10 are defined in FAIL. In addition,
many of the UUO's or IOT's mentioned in the monitor manual (Sailon
55) are defined in FAIL. These are:
1. Standard DEC system UUO's.
INIT ENTER LOOKUP USETO USETI UGETF MTAPE RELEAS CLOSE OUTBUF
INBUF CALLI CALL STATO STATZ GETSTS SETSTS OPEN RENAME IN OUT
INPUT OUTPUT
2. Stanford general.
SPCWAR UINBF UOUTBF FBREAD FBWRT MAIL SEND WRCV SRCV SKPME
SKPHIM
3. Stanford displays.
DPYCLR DPYPOS DPYSIZ DPYOUT UPGIOT UPGMVM UPGMVE
PPSEL PPACT PPREL PGIOT PGSEL
4. Stanford teletype.
TTYUUO TTCALL INCHRW INCHRS OUTCHR OUTSTR INCHWL INCHSL
GETLIN SETLIN RESCAN CLRBFI CLRBFO INSKIP
5. Stanford pseudo-teletype.
PTYUUO PTYGET PTYREL PTIFRE PTOCNT PTRD1S PTRD1W PTWR1S
PTWR1W PTRDS PTWRS7 PTWRS9 PTGETL PTSETL PTLOAD
SAILON 26.2 FAIL MANUAL MACROS (etc) 20
3.0 MACROS (etc)
Macros are strings of text, with names, and, optionally, with
substitutable arguments. They are used where the same or similar
pieces of text (code) are used in several places. A macro is defined
with the DEFINE statement. An example of its format is:
DEFINE FOO (AC,ADDRS)
{MOVNI AC,-3
IMUL AC,ADDRS
ADDI AC,37
MOVEM AC,ADDRS}
(< and > may be used in place of { and } ).
The effect of ths statement is that the assembler will store the text
between the { and the matching } in its memory and, whenever the
identifier FOO appears, the string of text will be substituted for
it. Also, the arguments which follow the occurance of FOO will be
subsitiuted in the string of text where AC and ADDRS appear. For
example, if:
FOO (3, FARB+7 )
appears in the program somewhere after the DEFINE above, it will
expand into the following:
MOVNI 3,-3
IMUL 3,FARB+7
ADDI 3,37
MOVEM 3,FARB+7
The arguments to a macro call (the 3, FARB+7 in the above example)
may be enclosed in parentheses (as above) or not. Thus:
FOO 3,FARB+7
would have the same effect.
3.1 MACRO BODY
The body of a macro (the text part) may be any string of characters
with the one restriction that the right and left curly brackets ({})
must be balanced (and the occurances of < and > must be balanced).
3.2 ARGUMENTS in definition.
Arguments in macro definitions must be identifiers. A list of them,
enclosed in parentheses, must appear after the macro name in the
definition. Any intervening text is ignored, except for a
concatenation character (see below). If no list of arguments appears
before the macro body, it is assumed that there are no arguments.
SAILON 26.2 FAIL MANUAL MACROS (etc) 21
Everywhere an identifier appears in the text (body) which is the same
as one of the arguments, that identifier will be replaced with the
string of text which corresponds to that argument when the macro is
called. Thus, if FUDLY is one of the arguments in the definition of
a macro, and the following appears in the body:
A+FUDLY B
the FUDLY will be recognized as an argument. But if the following
appears:
A+FUDLYB
then, since FUDLYB is an identifier and is different from FUDLY, it
will not be recognized as an argument. For inserting parts of
identifiers as arguments, see "concatenation" below.
3.3 Concatenation.
If a non-blank character other than a left parenthesis or a left
curly bracket or broket ( ( or { or < ) except carriage return or
line feed appears after the macro name in the definition, it is taken
as the concatenation character. This character may then be used to
delimit identifiers so that they will be recognized as arguments.
Appearances of this character will be deleted from the macro body if
they are immediately preceded or followed by an argument of the
macro.
3.4 MACRO Calls
A macro name may appear anywere and will be expanded to the MACRO, as
long as the name appears as an identifier and is considered as an
identifier by the assembler. (There are a few exceptions, listed
below). Thus, if FOO is a macro, it may appear alone on a line, in
the AC or index field or address filed, etc. However, if FOO appears
in a comment, or in the text argument of an ASCII statement, etc., it
will not be expanded, because it will not be considered an
identifier. Exceptions to this are the macro name in a DEFINE
statement, the symbol name in an OPDEF statement, and the formal
parameter list (list of arguments) in a DEFINE; macro names are never
expanded in these places.
Macros may be used recursively, that is, a macro may contain a macro
call or macro definition. However, if such macro calls are nested
too deep, the macro push-down list may overflow, resulting in a
monitor error message and terminating the assembly. If this occurs,
the /P switch should be used in the command string. Every occurrence
of /P in the command string causes the assembler to allocate an extra
200 (octal) words of memory for the macro push-down list.
SAILON 26.2 FAIL MANUAL MACROS (etc) 22
3.5 ARGUMENTS in macro calls.
Note: in the following discussion, right square bracket and right
broket ( ] and > ) will have the same effect as carriage return.
The list of arguments to a macro call may be enclosed in parentheses.
The arguments themselvs are separated by commas. The first argument
to the macro starts with the first character (including blank) after
the left parentheses, if the arguments are enclosed in parentheses or
with the first non-blank character after the macro name, if they are
not. Subsequent arguments start with the first character (inluding
space) after the comma which terminates the argument before. All
arguments terminate with the last character before the next comma, or
the right parenthesis if parentheses are used, or the first carriage
return or semicolon if parentheses are not used. Two commas in a
row, with no characters in between, indicate a null argument, i.e. an
argument consisting of no characters. The right parenthesis, if
parentheses are used, or the first carriage return, if they are not,
terminates the argument string. If more arguments are called for
than are supplied, the last ones are considered to be null (i.e.,
consist of no characters). If more arguments are supplied than are
called for, the extras are ignored by the macro processor. (See "How
much is eaten" below.)
There are two exceptions to the above. If the first character of an
argument is a left curly bracket ({) or broket (<), all characters up
to the matching right bracket (}) or broket (>) are taken as the
argument. In this way the argument may contain commas, parentheses,
etc., the only restriction being the balancing of the curly brackets
or brokets. The curly brackets (outer pair) or brokets are not
included as part of the argument. All characters between the right
curly bracket (}>) which ends the argument, and the next argument
terminator (comma, or carriage return if no parentheses, or right
parenthesis if parentheses) are ignored. In this way it is possible
to continue a list of arguments from one line to the next (i.e.
enclose the last argument on the line in curly brackets and put the
comma for it at the start of the next line.)
The other exception occurs if the first character of an argument is a
right arrow (→) (Note: the character back slash ( ) may be used for
the right arrow in teletype-prepared text.) In this case, the next
thing after the right arrow is considered to be an expression (and it
better be). The expression is evaluated (it better be defined, too)
and the value is converted to a string of ascii digits in the current
radix (radix hadn't ought to be 1). This string of digits is taken as
the argument. All characters from the end of the expression to the
next argument termination character (comma etc) are ignored.
SAILON 26.2 FAIL MANUAL MACROS (etc) 23
3.6 How much is eaten.
When a macro call appears, a certain amount of text is considered as
being part of the call, while the rest is not, and will be assembled.
For instance if:
DEFINE FOO (A) { A + 7/6}
has appeared, then when:
MOVEI A,FOO (3) (6) ; comment
appears, it will be assembled as:
MOVEI A,3+7/6 (6) ; comment
Thus, the text FOO (3) is considered to be part of the macro call,
and is "eaten".
A definite, if complicated, set of rules govern how much text gets
eaten in a macro call. If the macro was defined as having no
arguments, then only the macro name and any following spaces (or
tabs) are eaten. If the macro was defined as having arguments, and
the first non-blank character after the macro name is a
left-parenthesis, then everything from the macro name to the right
parenthesis which closes the argument list, inclusive, is eaten. If
the macro was defined as having arguments and the first non-blank
character is not a left parenthesis, then everything from the macro
name, to the comma or carriage return which terminates the last macro
argument used, is eaten. Thus, if parentheses are not used and too
few arguments are supplied, everything from the macro name to the
carriage return will be eaten. If parentheses are not used, and the
macro was defined as having arguments, and enough or too many
arguments are supplied, everything from the macro name to the comma
(or carriage return) which terminates the last argument used, will be
eaten.
Example -- if:
DEFINE FOO $(A,B) {A$B}
then:
MOVEI FOO 1,2, ,37(6)
will expand to:
MOVEI 12,37(6)
and the "FOO 1,2, " will have been eaten.
SAILON 26.2 FAIL MANUAL MACROS (etc) 24
3.7 FOR
The FOR statement serves, among other purposes and in a more general
and useful way, the same purpose that is poorly served in inferior
assemblers by the IRP and IRPC messes. There are 3 types of FOR;
they all have the same general form. They start with the word FOR
followed by a range specifier, followd by a string of text enclosed
in curly brackets and called the "argument list". The text has the
same form as the body of a macro, and the FOR expands into that
string of text, repeated once for each element in the range of the
FOR. The FOR may have one or two "formal arguments" which are
specified in the range specification. The FOR may also have a
concatenation character. If a concatenation character is desired, it
is specified by following the word FOR with the character @ followed
immediately by the concatenation character. Note that if a FOR is
used inside a macro, and concatenation of FOR arguments is desired,
it is necessary to have a concatenation character specified for the
FOR (which is different from the one for the macro, if any).
3.7.1 "IN" FOR
This is the type of FOR which replaces the outmoded IRP. The range
specification consists of one or two formal argument identifiers,
followed by either the identifier IN or the character ⊂, followed by
an argument list. The argument list has the same syntax as a macro
argument list, except that the list must be in parentheses. The
effect is that the body of the FOR is assembled once for each element
in the argument list, and that element is substituted for the first
(or only) formal argument each time. The second formal argument, if
present, will have the remainder of the argument list (starting with
the element following the one currently substituted for the first
argument) substituted for it.
Examples:
FOR A IN (QRN,{(<JRST 4,>)} STORP)
{MOVSI 13,A
PUSHJ P,GORP
}
will expand to:
MOVSI 13,QRN
PUSHJ P,GORP
MOVSI 13,(<JRST 4,>)
PUSHJ P,GORP
MOVSI 13,STORP
PUSHJ P,GORP
------------------------------
FOR ZOT,FUB ⊂ (A,B,C,D)
{ MOVEI ZOT,137 ; FUB LEFT
SAILON 26.2 FAIL MANUAL MACROS (etc) 25
}
will expand to:
MOVEI A,137 ; B,C,D LEFT
MOVEI B,137 ; C,D LEFT
MOVEI C,137 ; D LEFT
MOVEI D,137 ; LEFT
3.7.2 Character FOR
This type of FOR replaces IRPC. The range specifier consists of one
or two formal arguments followed by either the letter E or the
character ε, followed by a string of characters enclosed in curly
brackets. The only restriction on the string of characters is that
the curly brackets must balance. The body of the FOR is assembled
once for each character in the list, with that character substituted
for the first formal argument each time, and the rest of the string
(CDR) substituted for the second formal argument, if any.
Examples:
FOR ZOT,FUB ε {ABCD}
{ MOVEI ZOT,137 ; FUB LEFT
}
will expand to:
MOVEI A,137 ; BCD LEFT
MOVEI B,137 ; CD LEFT
MOVEI C,137 ; D LEFT
MOVEI D,137 ; LEFT
---------------------------------
FOR @$ QRN ε {AZ1Q5}
{ZORP$QRN←0
}
will expand to:
ZORPA←0
ZORPZ←0
ZORP1←0
ZORPQ←0
ZORP5←0
3.7.3 Arithmetic FOR
This type of FOR is similar to the ALGOL FOR. The range specifier
consists of one or two formal arguments followed by a left arrow (←)
followed by two or three expressions, separated by commas. The
expressions are like the two or three arguments of a FORTRAN DO
statement. The value of the first is the starting value, the value
SAILON 26.2 FAIL MANUAL MACROS (etc) 26
of the second is the ending value, and the value of the third is the
increment. If the third expression is not present, the increment is
taken as 1. The body of the FOR is assembled repeatedly, first for
the starting value, then for the starting value plus the increment,
etc. until it has been assembled once for each such value which is
less than or equal to the ending value. (Greater than or equal if the
increment is negative.) If the starting value is already greater than
the ending value (less than, for negative increment), the FOR body is
not assembled at all. For each repetition, the current
(corresponding) value is converted to ascii digits in the current
radix, and that string is substituted for the formal argument
(arguments). Note that all expressions must be defined, available,
and not relocatable.
Examples: (assume base 8)
FOR I←1+3, 25, 7
{ XWD FOO,I
}
will expand to:
XWD FOO,4
XWD FOO,13
XWD FOO,22
-------------------------------------
FOR @$ ZOT←4,11
{ZOTQ$ZOT : ZOT +3
}
will expand to:
ZOTQ4 : 4 +3
ZOTQ5 : 5 +3
ZOTQ6 : 6 +3
ZOTQ7 : 7 +3
ZOTQ10 : 10 +3
ZOTQ11 : 11 +3
3.8 REPEAT
For compatibility with a certain existing inferior assembler, the
REPEAT statement is included. The format is:
REPEAT n, { text }
where n is any defined available expression and the text is like a
macro body. The expression is evaluated and the text is assembled
that number of times, with a carriage return-line feed inserted at
its end each time.
SAILON 26.2 FAIL MANUAL MACROS (etc) 27
Example:
REPEAT 3, {0}
will expand to:
0
0
0
3.9 Conditional Assembly.
The conditional assembly op-codes (the IF's) differ from other
pseudo-ops in that, like macros, they will be recognized as the IF
op-codes wherever they appear, as long as the assembler sees them as
identifiers. Thus, IF's need not be the first things on lines.
3.9.1 Numeric IF's.
There are six numeric IF's. They are:
IFE, IFN, IFG, IFL, IFGE, IFLE
They stand for, respectively, if equal, if not equal, if greater
than, if less than, if greater than or equal to, if less than or
equal to. The format is as follows:
IFE exp, { text } or
IFE exp, < text >
The expression is evaluated, and if its value bears the indicated
relation (in this case equal) to zero, the text is assembled once;
otherwise it is not assembled, and does not appear as part of the
program. The text is like a macro body -- {} and <> must be
balanced.
Examples:
IFE 3, {ZOT}
will be skipped, but
IFGE 15, {JRST START}
will expand to:
JRST START
3.9.2 Text IF's
There are two text IF's. They are IFIDN and IFDIF which stand for if
identical and if different, respectively. The format is:
SAILON 26.2 FAIL MANUAL MACROS (etc) 28
IFIDN {text 1} {text 2} {text 3}
(<> are substitutable for the {}). The texts can be any string of
characters in which the curly brackets (or pointy brackets or
brokets) balance. For IFIDN, if the two strings text 1 and text 2 are
identical in each and every character, the string text 3 will be
assembled, otherwise it will not. For IFDIF, if text 1 and text 2
are identical, text 3 will not be assembled, otherwise it will.
3.9.3 Symbol IF's.
There are eight symbol IF's. There are IFDEF, IFNDEF, IFAVL, IFNAVL,
IFOP, IFNOP, IFMAC, IFNMAC. The format for these is:
IFDEF symbol, {text}
If the indicated condition is true for the symbol, the text is
assembled. Otherwise it is not. The ops come in pairs; if the first
of a pair is true, the second is false, if the first if false, the
second is true. IFDEF will be true if the symbol is defined as an
op-code (OPDEF), or as a macro, or if it has been defined as a label
(colon or left arrow) in this block or an outer block. In other
words, IFDEF will be true if the symbol could be used on a line by
itself (ignoring possible future definitions). IFNDEF is the
opposite of IFDEF. IFAVL will be true if the symbol is defined as an
op-code or macro or if it has been defined in this block, or declared
global in this block and defined in an outer block, or if it was
defined in an outer block with a down-arrow. In other words, IFAVL
will be true if the symbol is immediately available. IFOP will be
true if the symbol is defined as an op-code. IFMAC will be true if
the symbol is defined as a macro.
SAILON 26.2 FAIL MANUAL 29
APPENDIX I
COMMAND LANGUAGE
The basic format of a FAIL command is:
binary_file,listing_file ← source_file
File specifications consist of:
device : file
If device: is missing, DSK: is assumed. Either the binary or listing
file may be omitted (or both). If the listing is omitted, the comma
may be omitted too; if the binary is omitted, the comma must be
present.
Switches should follow file names and may be either of the slash
(e.g. "/x" ) or parens type (e.g. "(x)").
There are three types of switches: those that affect a device, in
which case the switch should appear after the name of the file to be
affected; those that affect the operation of the assembler as a
whole, in which case the switch may follow any file name; and the "P"
switch, discussed below.
Device-affecting switches:
N no listing of errors on TTY
R wait after each error as it is printed on TTY
S list symbol table
I ignore XLIST1
L don't list literal values with text.
C make a cref
U underline macro expansions on listing
Q do not convert character set on listing.
J turn on creffing
K turn off creffing
"P" switch: The macro push-down list is normally 200 locations long.
If a lot of recursion is used in macros, this may not be enough. The
macro PDL will be expanded by 200 words for every occurrence of the P
switch in the command string. Alternatively (#P) where # is a
number, may be used. For instance the following two will have the
same effect:
/P/P/P
(3P)